package
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;

	public class Container extends Sprite
	{
		private var length:uint;
		private var depths:Vector.<uint>;

		public function Container()
		{
			super();
			this.length = 0;
			this.depths = new Vector.<uint>();
		}

		public override function addChild(child:DisplayObject):DisplayObject
		{
			if (child && child.parent == null)
			{
				var depth:uint = this.length ? this.depths[this.length - 1] + 1 : 0;
				this.length++;
				this.depths.push(depth);
				return super.addChild(child);
			}
			return null;
		}

		public override function addChildAt(child:DisplayObject, index:int):DisplayObject
		{
			if (child && child.parent == null && index <= this.length)
			{
				var depth:uint = this.depths[index] ? this.depths[index] : this.depths[index] + 1;
				this.length++;
				this.depths.splice(index, 0, depth);
				return super.addChildAt(child, index);
			}
			return null;
		}

		public function addChildAtDepth(child:DisplayObject, depth:uint):DisplayObject
		{
			var index:int = this.getIndexByDepth(depth);
			if (child && child.parent == null && index <= this.length)
			{
				this.length++;
				this.depths.splice(index, 0, depth);
				return super.addChildAt(child, index);
			}
			return null;
		}

		public override function removeChild(child:DisplayObject):DisplayObject
		{
			if (child && child.parent == null)
			{
				var index:int = this.getChildIndex(child);
				this.length--;
				this.depths.splice(index, 1);
				return super.removeChild(child);
			}
			return null;
		}

		public override function removeChildAt(index:int):DisplayObject
		{
			if (index < this.length)
			{
				this.length--;
				this.depths.splice(index, 1);
				return super.removeChildAt(index);
			}
			return null;
		}

		public function removeChildAtDepth(depth:uint):DisplayObject
		{
			var index:int = this.getIndexByDepth(depth);
			if (index < this.length && this.depths[index] == depth)
			{
				this.length--;
				this.depths.splice(index, 1);
				return super.removeChildAt(index);
			}
			return null;
		}

		public function removeAllChildren():void
		{
			this.depths = new Vector.<uint>();
			while (this.length--)
			{
				super.removeChildAt(0);
			}
		}

		private function getIndexByDepth(depth:uint):int
		{
			var length:int = this.depths.length;
			var minimum:int = length ? 0 : 0;
			var maximum:int = length ? length - 1 : 0;
			var index:int = (minimum + maximum) / 2;
			var tempDepth:uint = 0;
			while (length)
			{
				index = (minimum + maximum) / 2;
				tempDepth = this.depths[index];
				if (depth > tempDepth)
				{
					minimum = index + 1 <= maximum ? index + 1 : index;
					index = minimum;
				}
				else if (depth < tempDepth)
				{
					maximum = index - 1 >= minimum ? index - 1 : index;
					index = maximum;
				}
				else if (depth == tempDepth)
				{
					return index;
				}
				if (minimum == maximum)
				{
					tempDepth = this.depths[index];
					if (depth > tempDepth)
					{
						return index + 1;
					}
					else if (depth < tempDepth)
					{
						return index;
					}
					else
					{
						return index;
					}
				}
			}
			return index;
		}
	}
}
